import sys
import os
import re
import struct
import time
import serial

SeriaHandle = ''

POLYNOMIAL = 0x1021
INITIAL_REMAINDER = 0xFFFF
FINAL_XOR_VALUE = 0x0000
WIDTH = 16
TOPBIT = (1 << (WIDTH - 1))
crcTable = {}
 
def crcInit():
	SHIFT = WIDTH - 8
	for step in range(0, 256):
		remainder = step << SHIFT
		for bit in range(8, 0, -1):
			if remainder & TOPBIT:
				remainder = ((remainder << 1) & 0xFFFF) ^ 0x1021
			else:
				remainder = remainder << 1
		crcTable[step] = remainder
 
def crcFast(data):
    remainder = 0xFFFF
    for n in range(len(data)):
        datan = data[n] ^ (remainder >> (WIDTH - 8))
        remainder = crcTable[datan] ^ ((remainder << 8)&0xFFFF)  
    remainder = remainder & 0xffff    
    return crcCalc(data) 

def crcCalc(data):
    crc = 0
    for n in range(len(data)):
        i = 0x80
        while i :
            if crc & 0x8000:
                crc = crc * 2
                crc = crc ^ 0x1021
            else:
                crc = crc * 2
            if data[n]&i :
                crc = crc ^ 0x1021
            crc = crc & 0xffff
            i = i >> 1
    crc = crc & 0xffff
    return crc

def formatStrToByte(target):
    buff = [] 
    for i in range(len(target)):
        buff.append(ord(target[i]))
    return buff

def parseConfig(line, config):
    ps = re.search('(\w+)\s*=\s*([\w\.]+)', line)
    if ps:
        config[ps.groups()[0]] = ps.groups()[1]

    
def ReadConfig(configPath, config):
    file = open(configPath, 'rb')
    for line in file.readlines():
        if line.startswith(';') :
            continue 
        ps = re.match('\[(\w+)\]', line)   
        if ps:
            print ps.groups()[0]
            #config[ps.groups()[0]] = {}
            continue
        parseConfig(line, config)
        #print line    
    file.close()
    
    
def FileTest(filePath):
    FileSize = os.path.getsize(filePath)
    print FileSize
    file = open(filePath, 'rb')
    filew = open('2.txt','w')
    while FileSize > 1024:
        str = file.read(1024)
        i = 0;
        format = ''
        while i < 1024:
            i = i +1;
            format = format+'b'
        stsr = struct.unpack(format, stsr)
        filew.write(stsr)
        FileSize = FileSize - 1024
    i = 0;
    format = ''
    while i < FileSize:
        i = i +1;
        format = format+'b' 
    stsr = file.read(FileSize)  
    #stsr = 'ab'    
    stsr = struct.unpack(format, stsr)
    print stsr
    sf = ','
    filew.write(' 0x'.join('%x' % x for x in stsr)) 
    filew.close()    
    file.close()

def getIModemCrc(buff):
    crc = []
    crc16 = crcCalc(buff)    
    crc.append((crc16&0xff00)>>8)
    crc.append(crc16&0x00ff)
    return crc

def debugPrint(title, data):
    print title
    data = struct.unpack('B'*len(data), data)
    print ' 0x'.join('%x' % x for x in data)

def debugPackPrint(style, data):
    data = struct.unpack(style*len(data), data)
    print ' 0x'.join('%02x' % x for x in data)

def getIModemHead(buffLen, sn):
    head = []
    if buffLen == 128:
        head.append(0x01)
    else:
        head.append(0x02)
    head.append(sn&0xff)
    head.append((~sn)&0xff)
    return head

def GetIModemStartFram(fileName, sn):
    head = getIModemHead(128, sn)    
    body = formatStrToByte(fileName)    
    body.append(0)
    fileSize = os.path.getsize(fileName)
    body += formatStrToByte('%d' % fileSize) 
    body.append(0x20)     
    body.append(0) 
    body += [0]*(128 - len(body))
    crc = getIModemCrc(body)  
    return head + body + crc    

def GetIModemDataFram(dataBuff, sn):
    buffLen = 0
    dataLen = len(dataBuff)
    if dataLen <= 128:
        buffLen = 128
    elif dataLen <= 1024:
        buffLen = 1024
    else:
        print 'error'    
    head = getIModemHead(buffLen, sn)
    body = list(struct.unpack('B'*len(dataBuff), dataBuff))
    if buffLen > len(body):
        body += [0x1a]*(buffLen - len(body))
    crc = getIModemCrc(body)  
    return head + body + crc
    
def GetIModemStopFram():
    head = getIModemHead(128, 0)
    body = [0]*128
    crc = getIModemCrc(body)  
    return head + body + crc 
    
def SendFile(filePath,com ,bandrate):
    sn = 0
    print 'start'
    SeriaHandle =  serial.Serial(com,bandrate)
    FileSize = os.path.getsize(filePath)
    print FileSize
    file = open(filePath, 'rb')    
    num = GetIModemStartFram(filePath, sn)
    sn += 1
    data = struct.pack('B'*len(num), *num)
    SeriaHandle.write(data)
    debugPrint('start', data)    
    time.sleep(8)   
    while FileSize > 1024:
        buff = file.read(1024)
        data = GetIModemDataFram(buff,sn)
        sn += 1
        data = struct.pack('B'*len(data), *data)
        SeriaHandle.write(data)
        debugPrint('data', data)
        time.sleep(2)
        FileSize = FileSize - 1024
    buff = file.read(FileSize)
    data = GetIModemDataFram(buff,sn)
    sn += 1
    data = struct.pack('B'*len(data), *data)
    SeriaHandle.write(data)
    debugPrint('start', data)
    time.sleep(2)    
    data = [0x04]
    data = struct.pack('B'*len(data), *data)
    stsr = struct.unpack('B'*len(data), data)
    for n in range(2):  
        SeriaHandle.write(data)
        debugPrint('end', data)
        time.sleep(2)    
    data = GetIModemStopFram()
    data = struct.pack('B'*len(data), *data)
    SeriaHandle.write(data)
    debugPrint('stop', data)
    time.sleep(2)
    file.close()    
    SeriaHandle.close()


def getIModemStream(binPath):
    flow = []
    sn = 0
    #tempData = [0x32]
    #tempData = struct.pack('B'*len(tempData), *tempData)
    #flow.append('2')
    FileSize = os.path.getsize(binPath)
    print 'binName: %s, fileSize: %d' %(binPath, FileSize) 
    tempData = GetIModemStartFram(binPath, sn)
    sn += 1
    tempData = struct.pack('B'*len(tempData), *tempData) 
    flow.append(tempData)  
    file = open(binPath, 'rb')    
    while FileSize > 1024:
        buff = file.read(1024)
        FileSize = FileSize - 1024
        tempData = GetIModemDataFram(buff,sn)        
        sn += 1
        tempData = struct.pack('B'*len(tempData), *tempData)
        flow.append(tempData)        
    buff = file.read(FileSize)
    tempData = GetIModemDataFram(buff,sn)
    sn += 1
    tempData = struct.pack('B'*len(tempData), *tempData)
    flow.append(tempData) 
    file.close()
    tempData = [0x04]
    tempData = struct.pack('B'*len(tempData), *tempData)
    flow.append(tempData)
    flow.append(tempData)
    tempData = GetIModemStopFram()
    tempData = struct.pack('B'*len(tempData), *tempData)
    flow.append(tempData)
    return flow

def uartSendIModem(streamData, com ,bandrate):
    if len(streamData) < 5:
        print 'streamData len error!'   
    print 'seriaSend,com=%s, bandrate=%s' %(com, bandrate)
    streamData.insert(0,'2')    
    seriaHandle = serial.Serial(com,bandrate)
    seriaHandle.write(streamData[0])
    debugPackPrint('B',streamData[0])
    print 'sleep(4)'
    time.sleep(4)
    seriaHandle.write(streamData[1])
    debugPackPrint('B',streamData[1])
    print 'sleep(8)'
    time.sleep(8)
    for n in range(2,len(streamData)):
        seriaHandle.write(streamData[n])
        debugPackPrint('B',streamData[n]);
        print 'sleep(2)'
        time.sleep(2)
    seriaHandle.close()

if __name__=="__main__":
    config = {}
    config_path = sys.argv[1]
    crcInit()
    ReadConfig(config_path, config)
    print config
    #SendFile(config['filename'],config['COM'],config['bandrate'])
    stream = getIModemStream(config['filename'])    
    uartSendIModem(stream, config['COM'],config['bandrate'])

      